﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Security;
using System.Runtime.InteropServices;

namespace System.Peppers.Win32
{
    /// <summary>
    /// Class for intalling assemblies to the GAC
    /// </summary>
    [SuppressUnmanagedCodeSecurity]
    public sealed class GacInstaller : IDisposable
    {
        private IAssemblyCache _assemblyCache = null;

        private bool CreateAssemblyCache()
        {
            int result = 0;
            if (_assemblyCache == null)
            {
                result = Fusion.CreateAssemblyCache(out _assemblyCache, 0);
            }
            return result == 0;
        }

        /// <summary>
        /// Adds a file to the GAC by its file path
        /// </summary>
        /// <param name="assembly">Path to assembly fiile</param>
        /// <returns>True if success</returns>
        public bool AddAssemblyToCache(string assembly)
        {
            if (!CreateAssemblyCache())
            {
                return false;
            }
            return _assemblyCache.InstallAssembly(IASSEMBLYCACHE_INSTALL_FLAG.IASSEMBLYCACHE_INSTALL_FLAG_FORCE_REFRESH, assembly, IntPtr.Zero) == 0;
        }

        /// <summary>
        /// Removes specified assembly from cache
        /// </summary>
        /// <param name="assembly">Assembly file name without its extension</param>
        /// <returns>True if success</returns>
        public bool RemoveAssemblyFromCache(string assembly)
        {
            if (!CreateAssemblyCache())
            {
                return false;
            }
            uint disposition = 0;
            return _assemblyCache.UninstallAssembly(IASSEMBLYCACHE_INSTALL_FLAG.IASSEMBLYCACHE_INSTALL_FLAG_FORCE_REFRESH, assembly, IntPtr.Zero, out disposition) == 0;
        }

        /// <summary>
        /// Checks if a dll it in the GAC, by it's name (no .dll extension)
        /// </summary>
        /// <param name="assembly">Assembly file name without its extension</param>
        /// <returns>True if found in GAC</returns>
        public bool IsAssemblyInCache(string assembly)
        {
            if (!CreateAssemblyCache())
            {
                return false;
            }
            return _assemblyCache.QueryAssemblyInfo(IASSEMBLYCACHE_INSTALL_FLAG.IASSEMBLYCACHE_INSTALL_FLAG_NONE, assembly, IntPtr.Zero) == 0;
        }
    
        #region IDisposable Members

        /// <summary>
        /// Disposes internal COM object
        /// </summary>
        public void  Dispose()
        {
 	        if (_assemblyCache != null)
            {
                Marshal.ReleaseComObject(_assemblyCache);
            }
        }

        #endregion
}
}
